package com.qk.management.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.qk.management.mapper.FileCleanMapper;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OssFileCleanService {

    @Autowired
    private FileCleanMapper fileCleanMapper;

    @Value("${aliyun.oss.bucket-name}")
    private String bucketName;

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.region}")
    private String region;

    // OSS客户端
    private OSS ossClient;

    @PostConstruct
    public void init() {
        try {
            // 使用EnvironmentVariableCredentialsProvider来获取环境变量中的认证信息
            com.aliyun.oss.ClientBuilderConfiguration clientBuilderConfiguration = new com.aliyun.oss.ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);

            this.ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(new EnvironmentVariableCredentialsProvider())
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException("OSS客户端初始化失败: " + e.getMessage(), e);
        }
    }

    @PreDestroy
    public void destroy() {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }

    /**
     * 获取OSS中所有文件
     */
    public List<String> getAllOssFiles() {
        List<String> fileList = new ArrayList<>();
        try {
            // 使用新的分页方式
            String nextMarker = null;
            do {
                com.aliyun.oss.model.ListObjectsRequest request = new com.aliyun.oss.model.ListObjectsRequest(bucketName);
                if (nextMarker != null) {
                    request.setMarker(nextMarker);
                }
                ObjectListing objectListing = ossClient.listObjects(request);

                for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                    fileList.add(objectSummary.getKey());
                }

                nextMarker = objectListing.getNextMarker();
            } while (nextMarker != null && !nextMarker.isEmpty());

        } catch (Exception e) {
            throw new RuntimeException("获取OSS文件列表失败", e);
        }
        return fileList;
    }

    /**
     * 获取指定时间后上传的OSS文件
     */
    public List<String> getOssFilesAfter(LocalDateTime startTime) {
        List<String> fileList = new ArrayList<>();
        try {
            Date startDate = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());

            // 使用新的分页方式
            String nextMarker = null;
            do {
                com.aliyun.oss.model.ListObjectsRequest request = new com.aliyun.oss.model.ListObjectsRequest(bucketName);
                if (nextMarker != null) {
                    request.setMarker(nextMarker);
                }
                ObjectListing objectListing = ossClient.listObjects(request);

                for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                    if (objectSummary.getLastModified().after(startDate)) {
                        fileList.add(objectSummary.getKey());
                    }
                }

                nextMarker = objectListing.getNextMarker();
            } while (nextMarker != null && !nextMarker.isEmpty());

        } catch (Exception e) {
            throw new RuntimeException("获取OSS文件列表失败", e);
        }
        return fileList;
    }

    /**
     * 删除OSS文件
     */
    public void deleteOssFile(String fileKey) {
        try {
            ossClient.deleteObject(bucketName, fileKey);
        } catch (Exception e) {
            throw new RuntimeException("删除OSS文件失败: " + fileKey, e);
        }
    }

    /**
     * 从完整URL中提取文件名（OSS对象键）
     */
    private String extractFileNameFromUrl(String fullUrl) {
        if (fullUrl == null || fullUrl.isEmpty()) {
            return null;
        }

        // 如果是完整URL，提取路径部分
        try {
            URI uri = new URI(fullUrl);
            String path = uri.getPath();
            // 移除开头的斜杠
            return path.startsWith("/") ? path.substring(1) : path;
        } catch (URISyntaxException e) {
            // 如果不是有效URL，直接返回原字符串
            return fullUrl;
        }
    }

    /**
     * 执行文件清理
     */
    /**
     * 执行文件清理
     */
    public void cleanFiles(LocalDateTime startTime) {
        try {
            List<String> ossFiles;
            if (startTime == null) {
                // 全量比对
                ossFiles = getAllOssFiles();
            } else {
                // 增量比对
                ossFiles = getOssFilesAfter(startTime);
            }

            // 将LocalDateTime转换为Date
            Date startDate = startTime != null ?
                    Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()) : null;

            // 获取数据库中的文件记录
            List<String> dbFiles = fileCleanMapper.selectAllImage(startDate);

            // 将数据库中的URL转换为OSS对象键进行比对
            Set<String> dbFileSet = dbFiles.stream()
                    .map(this::extractFileNameFromUrl)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 找出需要删除的文件（OSS中有但数据库中没有）
            List<String> filesToDelete = ossFiles.stream()
                    .filter(file -> !dbFileSet.contains(file))
                    .collect(Collectors.toList());

            // 删除多余文件
            for (String fileKey : filesToDelete) {
                deleteOssFile(fileKey);
                System.out.println("已删除OSS文件: " + fileKey);
            }

            System.out.println("本次共清理 " + filesToDelete.size() + " 个文件");
        } catch (Exception e) {
            throw new RuntimeException("文件清理失败", e);
        }
    }
}